// Example 14-3. Drawing labeled connected components

#include <algorithm>
#include <iostream>
#include <opencv2/core/ocl.hpp>
#include <opencv2/opencv.hpp>

using namespace std;

int main(int argc, char* argv[])
{
    std::cout << "IPP: " << cv::ipp::useIPP() << std::endl;           // 输出 1
    std::cout << "TBB Threads: " << cv::getNumThreads() << std::endl; // 输出 >1
    // std::cout << "OpenCL: " << cv::ocl::haveOpenCL() << std::endl;    // 输出 true
    cv::Mat img, img_edge, labels, centroids, img_color, stats;

    // load image or show help if no image was provided
    if ((argc != 2) || (img = cv::imread(argv[1], cv::IMREAD_GRAYSCALE)).empty()) {
        cout << "\nERROR: You need 2 parameters, you had " << argc << "\n" << endl;
        cout << "\nExample 14-3: Drawing labeled connected componnents\n"
             << "Call is:\n"
             << argv[0] << " <path/image>\n"
             << "\nExample:\n"
             << argv[0] << " ../HandIndoorColor.jpg\n"
             << endl;
        return -1;
    }

    cv::threshold(img, img_edge, 128, 255, cv::THRESH_BINARY);
    cv::imshow("Image after threshold", img_edge);

    int i, nccomps = cv::connectedComponentsWithStats(img_edge, labels, stats, centroids);
    cout << "Total Connected Components Detected: " << nccomps << endl;

    vector<cv::Vec3b> colors(nccomps + 1);
    colors[0] = cv::Vec3b(0, 0, 0); // background pixels remain black.
    for (i = 1; i <= nccomps; i++) {
        colors[i] = cv::Vec3b(rand() % 256, rand() % 256, rand() % 256);
        if (stats.at<int>(i - 1, cv::CC_STAT_AREA) < 100) {
            colors[i] = cv::Vec3b(0, 0, 0); // small regions are painted with black too.
        }
    }
    img_color = cv::Mat::zeros(img.size(), CV_8UC3);

    // Use parallel processing for pixel iteration
    cv::parallel_for_(cv::Range(0, img_color.rows), [&](const cv::Range& range) {
        for (int y = range.start; y < range.end; ++y) {
            const auto* label_row = labels.ptr<int>(y);
            auto* color_row = img_color.ptr<cv::Vec3b>(y);

            const auto colors_data = colors.data();
            for (int x = 0; x < img_color.cols; ++x) {
                const int label = *label_row++;
                CV_Assert(0 <= label && label <= nccomps);
                *color_row++ = colors_data[label];
            }
        }
    });

    cv::imshow("Labeled map", img_color);
    cv::waitKey();
    return 0;
}
